import {assert} from "chai";
import {NamedNode, Parser} from "n3";
import {RdfStore} from "rdf-stores";
import {CBDShapeExtractor} from "../../lib/CBDShapeExtractor";
import {rdfDereferencer} from "rdf-dereference";
import sinon, {SinonStub} from "sinon";
describe("Extracting logical edge cases", function () {
let fetchStub: SinonStub;
let shapeStore = RdfStore.createDefault();
let extractor: CBDShapeExtractor;
let dataStore = RdfStore.createDefault();
before(async () => {
// Mock the global fetch function
fetchStub = sinon.stub(global, "fetch");
// Mock response for the specific person URL
fetchStub
.withArgs("https://test.com/name.ttl")
.withArgs("https://test.com/name.ttl#Person1")
.resolves(
new Response(`
@prefix ex: .
@prefix foaf: .
<./name.ttl> ex:name "Pieter" .
ex:name "Peterson" .
`,
{
status: 200,
headers: {"Content-Type": "text/turtle"},
}
)
);
let readStream = (
await rdfDereferencer.dereference(
"./tests/04 - logical edge cases/shape.ttl",
{localFiles: true},
)
).data;
await new Promise((resolve, reject) => {
shapeStore.import(readStream).on("end", resolve).on("error", reject);
});
extractor = new CBDShapeExtractor(shapeStore);
let readStream2 = (
await rdfDereferencer.dereference(
"./tests/04 - logical edge cases/data.ttl",
{localFiles: true},
)
).data;
await new Promise((resolve, reject) => {
dataStore.import(readStream2).on("end", resolve).on("error", reject);
});
});
after(() => {
// Restore the original fetch function
fetchStub.restore();
});
it("Check whether the OR condition works - and check with recursion", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person1"),
new NamedNode("http://example.org/Shape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 7);
});
it("Check whether the OR condition works a second time as well", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person2"),
new NamedNode("http://example.org/PersonShape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 7);
});
it("Check whether it does an HTTP request if it doesn’t find the required properties on a node", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person3"),
new NamedNode("http://example.org/KnowsPieterShape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 4);
});
it("Check whether it finds the nodelink in a xone", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person4"),
new NamedNode("http://example.org/XoneWithNodeShape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 3);
});
it("Check whether a node link in a xone in a xone triggers an HTTP request", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person5"),
new NamedNode("http://example.org/TriggersHTTPShape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 3);
});
it("Check whether a circular XONE shape works", async () => {
let result = await extractor.extract(
dataStore,
new NamedNode("http://example.org/Person6"),
new NamedNode("http://example.org/CircularXoneShape"),
);
//let writer = new Writer();
//writer.addQuads(result);
//writer.end((err, res) => {console.log(res);});
assert.equal(result.length, 7);
});
});
describe("Check whether paths are correctly chained", async () => {
const shape = `
@prefix sh: .
@prefix ex: .
ex:innerShape
a sh:NodeShape ;
sh:property [
sh:path (ex:first ex:second);
] .
ex:outerShape
a sh:NodeShape ;
sh:property [
sh:path ex:inner;
sh:node ex:innerShape;
] .
`;
const data = `
@prefix ex: .
ex:false ex:second "Don't find me".
ex:true ex:first ex:trueInner.
ex:trueInner ex:second "Find me".
ex:subject ex:first ex:false;
ex:inner ex:true.
`;
let shapeStore = RdfStore.createDefault();
let extractor: CBDShapeExtractor;
let dataStore = RdfStore.createDefault();
const shapeQuads = new Parser().parse(shape);
const dataQuads = new Parser().parse(data);
shapeQuads.forEach((quad) => shapeStore.addQuad(quad));
dataQuads.forEach((quad) => dataStore.addQuad(quad));
extractor = new CBDShapeExtractor(shapeStore);
const entity = await extractor.extract(
dataStore,
new NamedNode("http://example.org/subject"),
new NamedNode("http://example.org/outerShape"),
);
it("Follows complex path inside inner node", async () => {
const findMe = entity.find((q) => q.object.value === "Find me");
assert.isTrue(!!findMe, "Find me is found");
});
it("Doesn't follow path if it is not part of the shape", async () => {
const findMe = entity.find((q) => q.object.value === "Don't find me");
assert.isTrue(!findMe, "Don't find me is not found");
});
});